package gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import utility.Constants;
import org.freixas.jcalendar.DateEvent;
import org.freixas.jcalendar.DateListener;
import org.freixas.jcalendar.JCalendarCombo;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;

import database.ActivitiesRange;
import database.Database;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JPanel;

final class ChartsView extends JFrame implements DateListener, Cloneable, ActionListener{

	private static final long serialVersionUID = 1;
	private final String PIE_CHART_TITLE = "Productivity Pie Chart";
	private final String LINE_CHART_TITLE = "Productivity Line Chart";
	private final String LINE_CHART_X_AXIS = "Dates";
	private final String LINE_CHART_Y_AXIS = "Hours";
	private DefaultPieDataset pieDataset = new DefaultPieDataset();
	private TimeSeriesCollection lineChartDataset = new TimeSeriesCollection();
	private final JCalendarCombo startDate; 
	private final JCalendarCombo endDate;
	private final JPanel dates;
	private final JComboBox datesRange;
	private JFreeChart pieChart;
	private JFreeChart lineChart;
	private JPanel charts = new JPanel();
	private ChartPanel pieChartPanel;
	private ChartPanel lineChartPanel;
	private final static String WINDOW_TITLE = "STCAL Graphs";
	private enum chartRange  {LAST_WEEK, LAST_MONTH, LAST_YEAR, ALL_RANGE, YESTERDAY};
	private JMenu preferences = new JMenu("GCal credentials");
	
	ChartsView(){
		super(WINDOW_TITLE);
		addWindowListener(new ShutMaintenance());
		setLocationRelativeTo(null);
		
		Constants.updateActivitiesList();
		Constants.activitiesList = new JComboBox(Constants.activities);
		Constants.activitiesList.setVisible(true);
		Constants.activitiesList.addActionListener(this);
		
		datesRange = new JComboBox(chartRange.values());
		datesRange.setEditable(false);
		datesRange.addActionListener(this);
		
		startDate = new JCalendarCombo();
		startDate.removeActionListener(this);
		
		startDate.setDate(new Date(System.currentTimeMillis()- Constants.WEEK_MILLIS));
		startDate.addDateListener(this);
		
		
		endDate = new JCalendarCombo(JCalendarCombo.DISPLAY_DATE, false);
		
		dates = new JPanel(); 
		dates.add(startDate);
		dates.add(endDate);
		dates.add(datesRange);
		dates.add(Constants.activitiesList);
		
		Constants.updateActivitiesList();
		charts = new JPanel(new GridLayout());
		
		updateData(startDate.getCalendar().getTime(), 
				   endDate.getCalendar().getTime(),
				   Constants.getSelectedActivityId());
		
		lineChart = createLineChart(lineChartDataset);
		lineChartPanel = new ChartPanel(lineChart);
		lineChartPanel.setVisible(true);
		lineChartPanel.setBackground(Color.WHITE);
		final GridBagConstraints c = new GridBagConstraints();

		charts.add(lineChartPanel,c);
		
		pieChart = createPieChart(pieDataset);
		pieChartPanel = new ChartPanel(pieChart);
		pieChartPanel.setVisible(true);
		
	//	c.ipady = 800;
		charts.add(pieChartPanel,c);
		
	//	if (membersNo > 1) pieChartPanel.setVisible(true);
		
		
		getContentPane().add(preferences);
		getContentPane().add(charts, BorderLayout.PAGE_START);
		getContentPane().add(dates, BorderLayout.PAGE_END);
		setVisible(true);
		pack();
	}
	
	private JFreeChart createPieChart(final DefaultPieDataset dataset){
		final JFreeChart pieChart = ChartFactory.createPieChart(PIE_CHART_TITLE, pieDataset, true, true, false);
		final PiePlot plot = (PiePlot) pieChart.getPlot();
		final StandardPieSectionLabelGenerator generator = new StandardPieSectionLabelGenerator();
	//	plot.setToolTipGenerator(this);
		plot.setLabelGenerator(generator);
		
		return pieChart;
	}
	
	private JFreeChart createLineChart(final TimeSeriesCollection dataset){
		JFreeChart lineChart = ChartFactory.createTimeSeriesChart(LINE_CHART_TITLE, LINE_CHART_X_AXIS ,LINE_CHART_Y_AXIS , lineChartDataset, true, true, false);
		lineChart.setBackgroundPaint(Color.WHITE);
		XYPlot plot = lineChart.getXYPlot();
		plot.setDomainCrosshairVisible(true);
		plot.setRangeCrosshairVisible(true);
		
		return lineChart;
	}
	
	private void updateData(final Date startTime, final Date endTime, final int selectedGroup){
		//final ActivitiesRange timeSpent = new ActivitiesRange(startTime, endTime,selectedGroup);
		
		/* final String[] groupActivities = Database.getGroupMembers(selectedGroup);
		if (groupActivities == null) throw new RuntimeException("Didn't retrieve from Database the group members of " + selectedGroup + ".\n"); */
		
		
		updateLineChart(startTime, endTime, selectedGroup);
		updatePieChart();
		/*
		membersNo = groupActivities.length;
		if (membersNo > 1){
			int i=0;
			do{
				pointer.activityName = groupActivities[i];
				pointer.timeSpent =  timeSpent.getActivityTime(pointer.activityName.toString());
				totalPieTime += pointer.timeSpent;
				i++;
				if (i < membersNo && pointer.timeSpent > 0){
					pointer.next = new List();
					pointer = pointer.next;
				}
			} while (i < membersNo);
			
			updatePieChart(activitiesList);
			pieChartPanel.setVisible(true);	
		}*/
	}
	
	private void updatePieChart(){
		/*pieDataset.clear();*/
		final int selectedActivityId = Constants.getSelectedActivityId();
		final ActivitiesRange timeSpent = new ActivitiesRange(startDate.getDate(), endDate.getDate(), selectedActivityId);
		pieDataset.setValue(Database.getActivityName(selectedActivityId), timeSpent.getActivityTime());
		
		if (pieChartPanel != null){pieChartPanel.setVisible(true);
		charts.validate();}
		pack();
	}
	
	private void updateLineChart(Date startDate, final Date endDate, final int activityId){
		final TimeSeries timeSeries = new TimeSeries(activityId, null, null);
		
		while(startDate.before(endDate)){
			final Date tomorrow = new Date(startDate.getTime() + Constants.DAY_MILLIS);
			final ActivitiesRange timeSpent = new ActivitiesRange(startDate, tomorrow,activityId);
			//timeSpent.ChangeDateRange(startDate,tomorrow);
			final int time = (int) timeSpent.getActivityTime();
			if (time > 0){ 
				System.out.println("time: " + time + ", " + startDate.toString() + ", " + tomorrow.toString());
				if (time > 24) throw new RuntimeException();
				else 
					timeSeries.add(new Day(startDate),time);
			}
			startDate = tomorrow;
		}
		lineChartDataset.addSeries(timeSeries);
	}
	/*
	private double average(final long nominator, long denominator){
		if (denominator == 0) return 0;
		double result =  (double) (nominator/denominator);
		final int dP = 2;
		BigDecimal bd = new BigDecimal(result);
		bd.setScale(dP, BigDecimal.ROUND_HALF_UP);
		return bd.doubleValue();
	}
	
	private double percentage(final long nominator, final long denominator){
		return average(nominator*100, denominator); 		
	}
	*/
	private Date withInRange(final Date minDate, final Date maxDate, final Date givenDate, boolean min){
		return (! givenDate.before(minDate) && givenDate.before(maxDate))? givenDate : (min)? minDate: maxDate;
	}
	
	public void dateChanged(DateEvent e){
			final int selectedActivityId = Constants.getSelectedActivityId();
			final Date firstDate = Database.getFirstDate(selectedActivityId);
			final Date lastDate = Database.getLastEndDate(selectedActivityId);
		
			final Date selectedStart = new Date(startDate.getCalendar().getTimeInMillis());
			final Date selectedEnd = new Date(endDate.getCalendar().getTimeInMillis());
			pieDataset.clear();
			updateData(withInRange(firstDate,lastDate,selectedStart,true),withInRange(firstDate,lastDate,selectedEnd,false),selectedActivityId);
	}
	
	public void actionPerformed(ActionEvent e){
		final int selectedActivityId = Constants.getSelectedActivityId();
		final Date firstDate = Database.getFirstDate(selectedActivityId);
		final Date lastDate = Database.getLastEndDate(selectedActivityId);
		Date selectedDate = new Date(System.currentTimeMillis()  - Constants.WEEK_MILLIS);
		
		if (e.getSource() == datesRange){
			final chartRange rangeSelected = (chartRange) datesRange.getSelectedItem();
			switch(rangeSelected){
			case LAST_WEEK: selectedDate = withInRange(firstDate,lastDate,selectedDate,true);
			break;
			case LAST_MONTH: selectedDate = withInRange(firstDate,lastDate,new Date(selectedDate.getTime()- Constants.MONTH_MILLIS),true);
			break;
			case LAST_YEAR: selectedDate = withInRange(firstDate,lastDate,new Date(selectedDate.getTime()- Constants.YEAR_MILLIS),true);
			break;
			case YESTERDAY: selectedDate = withInRange(firstDate,lastDate,new Date(selectedDate.getTime()- Constants.DAY_MILLIS),true);
			break;
			default: selectedDate = firstDate;
			}
			startDate.setDate(selectedDate);
			endDate.setDate(lastDate);
		}
		else if (e.getSource() == Constants.activitiesList) updateData(startDate.getCalendar().getTime(),endDate.getCalendar().getTime(), selectedActivityId);

	}
	/*
	@SuppressWarnings("unchecked")
	public String generateToolTip(PieDataset dataset, Comparable key) {
		final int activityId = (Integer) key;
		/*
        if (dataset == null) throw new RuntimeException("dataset " + dataset + ", activityId: " + activityId + ".\n"); 
        
        final int grossTotal = Database.getTotal(activityId);
        final int grossDays = (int) ((grossTotal  > 0)? (Database.getLastEndDate(activityId).getTime() - Database.getFirstDate(activityId).getTime())/Constants.DAY_MILLIS : 0); 
        
        final double grossAverage = average(grossTotal, grossDays);
        
        int grossGroupTotal = Database.getGroupTotal(Constants.getSelectedActivityId()); 
        final double grossPercent = percentage(grossTotal, grossGroupTotal);
        
        long specifiedTotal =  dataset.getValue(key).longValue()/Constants.HH_MILLIS;//Constants.db.getTotal(key.toString()).divide(new BigInteger(Long.toString(Constants.HH_MILLIS))).longValue(); //dataset.getValue(key).longValue()/Constants.HH_MILLIS - grossTotal;
        
        final double specifiedGrossPercent = percentage(specifiedTotal, grossTotal); //need method that gets total of all members
        
        final double specifiedPercent = percentage(specifiedTotal, (totalPieTime/Constants.MM_MILLIS));
        final long specifiedDays = (globalEndTime.getTime() - globalStartTime.getTime())/Constants.DAY_MILLIS;
        
        final double specifiedAverage = average(specifiedTotal, specifiedDays);
        
        String timeSpan = "";
        if (specifiedTotal > 0) timeSpan = "timespan total: " + specifiedTotal + ",h, total dd: " + specifiedDays+ ", timespan average: " + specifiedAverage + ", timespan percentage: " + specifiedPercent + "%, ... over all time: " + specifiedGrossPercent + "% ||";
        
        String gross ="";
        if (grossTotal > 0) gross = "All time total: " + grossTotal + " h,   Total dd: " + grossDays + ", All time Average: " + grossAverage + ", All time percent: " + grossPercent + "% ||";
        
        final String activity = Database.getActivityName(activityId);
        return activity + ": " + timeSpan + " " + gross;
    }*/
}